package com.huan.study.esapi.documentapi;

import com.huan.study.esapi.AbstractEsApi;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.core.GetSourceRequest;
import org.elasticsearch.client.core.GetSourceResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.io.IOException;

/**
 * 文档的增删该查
 *
 * @author huan.fu 2021/4/22 - 下午2:59
 */
public class DocumentCrudApi extends AbstractEsApi {
    // 这个索引是提前建立的
    private static final String INDEX_NAME = "project";
    // location geo_point类型需要在创建索引的时候指定

    @DisplayName("查询索引下所有的文档")
    @Test
    public void matchAllQuery() throws IOException {
        SearchRequest request = new SearchRequest();
        request.indices(INDEX_NAME);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(
                QueryBuilders.matchAllQuery()
        );
        request.source(searchSourceBuilder);
        System.out.println("request: " + request);
        SearchResponse searchResponse = client.search(request, RequestOptions.DEFAULT);
        System.out.println("response: " + searchResponse);
    }

    /**
     * https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.12/java-rest-high-document-get.html
     */
    @DisplayName("根据id获取文档")
    @Test
    public void fetchData() throws IOException {
        GetRequest request = new GetRequest();
        request.index(INDEX_NAME);
        request.id(String.valueOf(1260138935238000640L));
        // 路由，可以不用设置，但是如果在添加数据的时候设置了，那么在查询数据的时候也需要设置
        request.routing(String.valueOf(1260138935238000640L));

        // 设置返回那些字段
        String[] includes = new String[]{"city_*", "project_id"};
        String[] excludes = new String[]{"city_name"};
        FetchSourceContext fetchContext = new FetchSourceContext(true, includes, excludes);
        request.fetchSourceContext(fetchContext);
        System.out.println("request: " + request);
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        System.out.println("response: " + response);
    }

    /**
     * https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.12/java-rest-high-document-get-source.html
     */
    @DisplayName("获取文档的部分字段")
    @Test
    public void getDocumentSource() throws IOException {
        GetSourceRequest request = new GetSourceRequest(INDEX_NAME, String.valueOf(1260138935238000640L));
        String[] includes = new String[]{};
        String[] excludes = new String[]{"city_id"};
        // fetchSource 必须为true
        request.fetchSourceContext(new FetchSourceContext(true, includes, excludes));
        System.out.println("request: " + request);
        GetSourceResponse response = client.getSource(request, RequestOptions.DEFAULT);
        System.out.println("response: " + response);
    }

    @DisplayName("判断文档是否存在")
    @Test
    public void existsDocument() throws IOException {
        GetRequest request = new GetRequest(INDEX_NAME, String.valueOf(1260138935238000640L));
        // 此处设置成false，不需要返回_source数据
        request.fetchSourceContext(new FetchSourceContext(false));
        // 禁止返回 stored 字段
        request.storedFields("_none_");
        System.out.println("request: " + request);
        boolean exists = client.exists(request, RequestOptions.DEFAULT);
        System.out.println("response: " + exists);
    }

    /**
     * https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.12/java-rest-high-document-index.html
     */
    @DisplayName("文档不存在-添加文档，文档存在-替换文档")
    @Test
    public void indexDocument() throws IOException {
        IndexRequest request = new IndexRequest(INDEX_NAME);
        // 根据id判断文档是否存在
        String id = String.valueOf(1260138935238000640L);
        request.id(id);
        // 当时 index 是，多次执行，如果下方的json字符串增加或删除了字段，则最后的结果以最后一次的json字符串为准，因为是替换文档
        request.opType(DocWriteRequest.OpType.INDEX);
        // 设置路由键，默认是id
        request.routing(id);

        // 楼盘信息
        String projectInfoJson = "{" +
                "\"project_id\":\"1260138935238000640\"," +
                "\"city_name\":\"上海市\"," +
                "\"filing_name\":\"上海新城金郡\"," +
                "\"location\":\"31.226581,121.393430\"," +
                "\"city_id\":\"785\"" +
                "}";

        request.source(projectInfoJson, XContentType.JSON);

        System.out.println("request: " + request);
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        System.out.println("response: " + response);
    }

    /**
     * https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.12/java-rest-high-document-index.html
     */
    @DisplayName("文档不存在-添加文档，文档存在-报错")
    @Test
    public void createDocument() throws IOException {
        IndexRequest request = new IndexRequest(INDEX_NAME);
        // 根据id判断文档是否存在
        String id = String.valueOf(1260138935238000640L);
        request.id(id);
        // 当是 CREATE 时，文档存在，则报错
        request.opType(DocWriteRequest.OpType.CREATE);
        // 设置路由键，默认是id
        request.routing(id);

        // 楼盘信息
        String projectInfoJson = "{" +
                "\"project_id\":\"1260138935238000640\"," +
                "\"city_name\":\"上海市\"," +
                "\"filing_name\":\"上海新城金郡\"," +
                "\"location\":\"31.226581,121.393430\"," +
                "\"city_id\":\"785\"" +
                "}";

        request.source(projectInfoJson, XContentType.JSON);

        System.out.println("request: " + request);
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        System.out.println("response: " + response);
    }

    /**
     * https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.12/java-rest-high-document-update.html
     */
    @DisplayName("更新文档-更新部分字段")
    @Test
    public void updateDocumentField() throws IOException {
        UpdateRequest request = new UpdateRequest(INDEX_NAME, String.valueOf(1260138935238000640L));
        String projectInfoJson = "{" +
                "\"project_id\":\"1260138935238000640\"," +
                "\"filing_name\":\"上海新城金郡(新)\"" +
                "}";
        request.doc(projectInfoJson, XContentType.JSON);
        // 更新冲突(版本冲突)之后，尝试多少次。
        request.retryOnConflict(3);
        // 获取 _source
        // request.fetchSource(true);
        System.out.println("request: " + request);
        UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
        System.out.println("response:" + response);
    }

    /**
     * https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.12/java-rest-high-document-delete.html
     */
    @DisplayName("删除文档")
    @Test
    public void deleteDocument() throws IOException {
        DeleteRequest request = new DeleteRequest(INDEX_NAME, String.valueOf(1260138935238000640L));
        System.out.println("request: " + request);
        DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
        System.out.println("response: " + response);
    }
}
